<?php
/**
 * Connector class to MySQL database and RAIL.
 * Provides methods to login an rail_user, contains the rail_root and a MySQL wrapper.
 * 
 * Use this file to be include into your own PHP scripts.
 * Provides also an autoload function and some basic constants.
 *
 **
 *
 * PHP versions 5
 * See http://www.open-rail.org for more informations.
 *
 **
 * Copyright (C)
 *
 * This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as
 * published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty
 * of ERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software
 * Fundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA
 *
 **
 * @author Bastian Schröder <bastian@open-rail.org>
 * @version 2009-05-14
 * @package rail
 */
require_once( 'rail_constants.inc.php' );
require_once( 'rail_mimetypes.inc.php' );
require_once( 'rail_autoload.func.php' );

class rail_connector {
	
	/**
	 * A prefix string for MySQL tables.
	 *
	 * @var mysql_table_prefix
	 */
	public $mysql_table_prefix;

	/**
	 * The MySQL database connector.
	 *
	 * @var mysqli
	 */
	public $mysqli;

	/**
	 * Current loged in rail_user.
	 *
	 * @var rail_user
	 */
	private $rail_user;

	/**
	 * The rail_root object.
	 *
	 * @var rail_root
	 */
	private $rail_root;

	/**
	 * Count number of database requests, use in debug sessions.
	 *
	 * @var request_counter
	 */
	private $request_counter = 0;


	/**
	 * Constructor
	 * Handle MySQL connection and login special rail_user 'guest'.
	 *
	 * @exception rail_exception
	 * @param string $pDatabase MySQL database name
	 * @param string $pUser MySQL user
	 * @param string $pPasswd MySQL password
	 * @param string $pServer MySQL server (optional)
	 * @param string $pTablePrefix MySQL table prefix  (optional)
	 */
	public function __construct ( $pDatabase, $pUser, $pPasswd, $pServer = 'localhost', $pTablePrefix = 'rail_' ) {
		// set mxsql table prefix
		$this->mysql_table_prefix = substr( $pTablePrefix, -1 ) == '_' || strlen( $pTablePrefix ) == 0 ? $pTablePrefix : $pTablePrefix . '_';
		
		// connect to mysql server
		$this->mysqli = new mysqli( $pServer, $pUser, $pPasswd );
		if ( mysqli_connect_errno() )
			throw new rail_exception( null, mysqli_connect_error() );

		// select table
		$this->mysqli->select_db( $pDatabase );
		if ( $this->mysqli->errno )
			throw new rail_exception( null, "Can't access databases: '$pDatabase'" );

		// check wheater databases is a RAIL tree
		$data = $this->mysqli->query( 'SHOW tables;' );
		$search_array = array( $this->mysql_table_prefix.'objects', $this->mysql_table_prefix.'objects_attributes');
		$i = 0;
		while( ($data_row = $data->fetch_assoc()) )
			if( in_array($data_row["Tables_in_$pDatabase"], $search_array) ) $i ++;
		if( $i != count($search_array) )
			throw new rail_exception( null, "Databases '$pDatabase' dosn't contains a RAIL tree." );

		// hard login guest user. get user with username guest and the lowesed rail_id.
		$guest_id = $this->send_request(
			"SELECT
				" . $this->mysql_table_prefix . "objects.id
			 FROM
			 	" . $this->mysql_table_prefix . "objects," . $this->mysql_table_prefix . "objects_attributes
			 WHERE
			 	" . $this->mysql_table_prefix . "objects.id = " . $this->mysql_table_prefix . "objects_attributes.object AND
			 	" . $this->mysql_table_prefix . "objects.`type`='RAIL_USER' AND
				" . $this->mysql_table_prefix . "objects_attributes.`attribute` = 'OBJ_NAME' AND
				" . $this->mysql_table_prefix . "objects_attributes.`value` = 'guest'
			ORDER BY
				`id` DESC
			LIMIT 1;"
		)->fetch_assoc();
		$this->rail_user = new rail_user( $this, $guest_id[ 'id' ] );
	}


	/**
	 * Disconnected from RAIL and MySQL.
	 *
	 */
	public function disconnect () {
		$this->mysqli->close();
		unset( $this->mysqli );
		unset( $this->rail_user );
		unset( $this->rail_root );
	}


	/**
	 * Get number of database requests. Helpful to optimize the count of MySQL requests.
	 *
	 * @return int
	 */
	public function get_request_count () {
		return $this->request_counter;
	}


	/**
	 * Get the rail_root object.
	 *
	 * @return rail_root
	 */
	public function get_root () {
		if( !$this->rail_root instanceof rail_object ){
			$data = $this->send_request( "SELECT `id` FROM " . $this->mysql_table_prefix . "objects WHERE `environment`='0' AND `type`='RAIL_ROOT' ORDER BY `id` LIMIT 1" )->fetch_assoc();
			$this->rail_root = new rail_root( $this, $data[ 'id' ] );
		}

		return $this->rail_root;
	}


	/**
	 * Get current loged in rail_user.
	 *
	 * @return rail_user
	 */
	public function get_user () {
		return $this->rail_user;
	}


	/**
	 * Try to login a rail_user. Return loged in rail_user or throw an exception.
	 *
	 * @exception rail_exception
	 * @param  rail_user $pUser
	 * @param string $pPasswd
	 * @return rail_user
	 */
	public function login( $pUser, $pPasswd ) {
		$data = $this->send_request( "
			SELECT
				" . $this->mysql_table_prefix . "objects.id,
				" . $this->mysql_table_prefix . "objects_attributes.`attribute`,
				" . $this->mysql_table_prefix . "objects_attributes.`value`
			 FROM
			 	" . $this->mysql_table_prefix . "objects,
			 	" . $this->mysql_table_prefix . "objects_attributes
			 WHERE
			 	" . $this->mysql_table_prefix . "objects.id = " . $this->mysql_table_prefix . "objects_attributes.`object`
			 	AND " . $this->mysql_table_prefix . "objects.`type`='RAIL_USER'
			 	AND (
			 		( " . $this->mysql_table_prefix . "objects_attributes.`attribute` = 'OBJ_NAME' AND
			 		  " . $this->mysql_table_prefix . "objects_attributes.`value` = '". trim( $pUser ) . "'
			 		)
			 		OR " . $this->mysql_table_prefix . "objects_attributes.`attribute` = 'RAIL_PASSWD'
			 	)
		" );

		// get object id and passwd from data
		$id = null;
		while( ($data_row = $data->fetch_assoc()) ){
			if( 
				( $id == null && $data_row[ 'attribute' ] != 'OBJ_NAME' ) ||
				( $id != null && $data_row[ 'id' ] != $id )
			)
				continue;

			if( $data_row[ 'attribute' ] == 'OBJ_NAME' )
				$id = $data_row[ 'id' ];
			else {
				$passwd = $data_row[ 'value' ];
				break;
			}
		}
		
		// throw exceptions if user with this passwd dosn't exist.
		if( $id == null || $passwd != md5( $pPasswd ) )
			throw new rail_exception( null, 'Access denied: password or user failure!' );

		// return loged in rail_user.
		$this->rail_user = new rail_user( $this, $id );
		return $this->get_user();
	}


	/**
	 * Send an MySQL multi_query to database and return the results as array. Return a single result object if
	 * the query contains only one result. Increment the request counter and wrap all MySQL errors with a
	 * rail_exception.
	 *
	 * @exception rail_exception
	 * @param string $pQuery MySQL multi_query
	 * @return mixed
	 */
	public function send_request( $pQuery ){
		$results = array();

		// get mysqli query results
		if( $this->mysqli->multi_query( $pQuery ) ){
			do{
				if( ($result = $this->mysqli->store_result()) )
					$results[] = $result;
			} while( $this->mysqli->next_result() );
		}
		if ( mysqli_errno( $this->mysqli ) )
			throw new rail_exception( null, mysqli_error( $this->mysqli ) );

		// increment debug counter
		$this->request_counter += 1;

		return count( $results ) == 0 ? $this->mysqli->insert_id : ( count($results) <= 1 ? $results[ 0 ] : $results );
	}

} // End of rail_connector
?>